package com.ruoyi.user.service.impl;


import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baomidou.mybatisplus.generator.IFill;
import com.ruoyi.common.core.constant.CacheConstants;
import com.ruoyi.common.core.enums.CacheKey;
import com.ruoyi.common.core.pojo.result.PageUtils;
import com.ruoyi.common.core.pojo.result.Pages;
import com.ruoyi.common.core.pojo.vo.TokenVO;
import com.ruoyi.common.core.utils.CollectionUtils;
import com.ruoyi.common.core.utils.CommonUtils;
import com.ruoyi.common.core.utils.RandomUtils;
import com.ruoyi.common.redis.cache.CacheTemplate;
import com.ruoyi.common.security.service.TokenService;
import com.ruoyi.system.api.model.LoginUser;
import com.ruoyi.system.api.model.user.AppDressInfo;
import com.ruoyi.system.api.model.user.AppUser;
import com.ruoyi.user.mapper.UserMapper;
import com.ruoyi.user.model.constant.UserConstant;
import com.ruoyi.user.model.factory.LoginStrategyContext;
import com.ruoyi.user.model.pojo.entity.Attention;
import com.ruoyi.user.model.pojo.entity.Dress;
import com.ruoyi.user.model.pojo.entity.User;
import com.ruoyi.user.model.pojo.request.app.*;
import com.ruoyi.user.model.pojo.request.crm.CrmSearchUserRequest;
import com.ruoyi.user.model.pojo.result.UserSearchInfo;
import com.ruoyi.user.model.pojo.result.app.UserBasicsInfo;
import com.ruoyi.user.model.pojo.result.crm.CrmUserInfoResult;
import com.ruoyi.user.service.*;
import io.rong.RongCloud;
import io.rong.models.response.TokenResult;
import io.rong.models.user.UserModel;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.security.crypto.factory.PasswordEncoderFactories;
import org.springframework.security.crypto.keygen.KeyGenerators;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


@Slf4j
@Service
public class UserServiceImpl extends ServiceImpl<UserMapper, User> implements IUserService {
    //    @Autowired
//    private AlipayConfig aliConfig;
    @Autowired
    private RongCloud rongCloud;
    @Autowired
    @Lazy
    private IAttentionService attentionService;
    @Autowired
    @Lazy
    private IUserFriendService userFriendService;
    @Autowired
    @Lazy
    private IUserLikeBackService iUserLikeBackService;
    @Autowired
    @Lazy
    private IUserBlackService userBlackService;
    @Autowired
    private UserMapper userMapper;
    @Autowired
    private TokenService tokenService;
    @Autowired
    private IDressService iDressService;


    @Override
    public List<UserSearchInfo> getUserList(List<User> users, Long userId) {
        List<UserSearchInfo> userSearchInfos = new ArrayList<>();
        for (User user : users) {
            UserSearchInfo build = UserSearchInfo.builder()
                    .id(user.getId())
                    .phone(user.getPhone())
                    .photo(user.getPhoto())
                    .nickName(user.getNickName())
                    .interestHobby(user.getInterestHobby())
                    .personalityName(user.getPersonalityName())
                    .isAttention(attentionService.isAttention(userId, user.getId()))
                    .fansCount(attentionService.beAttentionCount(user.getId()))
                    .noteName(Optional.ofNullable(attentionService.findById(userId, user.getId())).orElse(new Attention()).getNoteName())
                    .isBlack(userBlackService.isUserBlack(userId, user.getId()))
                    .build();
            userSearchInfos.add(build);
        }
        return userSearchInfos;
    }

    @Override
    public void verifyCode(String phone, String secretKey) {
        String cache = CacheTemplate.getCache(phone, String.class);
        Assert.notNull(cache, "验证码失效");
        Assert.isTrue(cache.equals(secretKey), "验证码输入错误");
    }

    @Override
    public Set<Long> attention(Long userId) {
        return attentionService.attentionUserIds(userId);
    }

    @Override
    public Pages<UserSearchInfo> searchUser(AppSearchUserRequest request, Long userId) {
        Page<User> userPage = PageUtils.initPage(request, User.class);
        Page<UserSearchInfo> page = userMapper.searchUser(userPage, request, userId);
        for (UserSearchInfo record : page.getRecords()) {
            record.setIsAttention(attentionService.attention(userId, record.getId()));
            record.setFansCount(attentionService.beAttentionCount(record.getId()));
            record.setIsBlack(userBlackService.isUserBlack(userId, record.getId()));
        }
        return PageUtils.pages(page);
    }

    @Override
    public Integer isAttention(Long userId, Long aimUserId) {
        return attentionService.isAttention(userId, aimUserId);
    }

    @Override
    public Pages<CrmUserInfoResult> listPage(CrmSearchUserRequest request) {
        Page<User> userPage = PageUtils.initPage(request, User.class);
        Page<User> page = lambdaQuery()
                .and(StringUtils.hasText(request.getSearch()),
                        wapper -> wapper.like(User::getNickName, request.getSearch())
                                .or()
                                .like(User::getName, request.getSearch())
                ).orderByDesc(User::getCreateTime)
                .page(userPage);
        List<CrmUserInfoResult> crmUserList = getCrmUserList(page.getRecords());
        return PageUtils.pages(page, crmUserList);
    }

    @Override
    public boolean updateUser(Long userId, AppUpdateUserRequest request) {
        User user = getById(userId);
        user.setPhoto(request.getPhoto());
        user.setNickName(request.getNickName());
        user.setBackgroundUrl(request.getBackgroundUrl());
        updateById(user);
        CacheTemplate.setCache(CacheKey.USER_INFO.getKey(String.valueOf(userId)), user, 3L, TimeUnit.DAYS);
        return true;
    }

    @Override
    public boolean forbiddenAndrelieve(Long userId, Integer status) {
        User user = getById(userId);
        user.setStatus(status);
        updateById(user);
        LoginUser loginUser = new LoginUser();
        loginUser.setUserid(userId);
        loginUser.setStatus(status);
        CacheTemplate.setCache(CacheConstants.LOGIN_USER_KEY + userId, loginUser, 10L, TimeUnit.DAYS);
        CacheTemplate.setCache(CacheKey.USER_INFO.getKey(String.valueOf(userId)), user, 10L, TimeUnit.DAYS);
        return true;
    }

    @Override
    public Set<Long> getNewUser() {
        Calendar instance = Calendar.getInstance();
        instance.setTime(new Date());
        instance.add(Calendar.MONTH, -1);
        return lambdaQuery()
                .ge(User::getCreateTime, instance.getTime())
                .list().stream().map(User::getId).collect(Collectors.toSet());
    }

    @Override
    public Set<Long> getCityWide(Long userId) {
        User user = getById(userId);
        if (CommonUtils.isNull(user)) return CollectionUtils.emptySet();
        return lambdaQuery().eq(User::getProvince, user.getProvince()).list().stream().map(User::getId).collect(Collectors.toSet());
    }

    CrmUserInfoResult getInfo(User user) {
        return CrmUserInfoResult.builder()
                .id(user.getId())
                .photo(user.getPhoto())
                .name(user.getName())
                .age(user.getAge())
                .nickName(user.getNickName())
                .imUsername(user.getImUsername())
                .phone(user.getPhone())
                .backgroundUrl(user.getBackgroundUrl())
                .sex(user.getSex())
                .identity(user.getIdentity())
                .interestHobby(user.getInterestHobby())
                .isAuth(user.getIsAuth())
                .province(user.getProvince())
                .personalityName(user.getPersonalityName())
                .placeServer(user.getPlaceServer())
                .loginTime(user.getLoginTime())
                .photoWall(user.getPhotoWall())
                .age(user.getAge())
                .createTime(user.getCreateTime())
                .status(user.getStatus())
                .build();
    }


    List<CrmUserInfoResult> getCrmUserList(List<User> users) {
        return users.stream().map(user -> {
            return getInfo(user);
        }).collect(Collectors.toList());
    }


    @Override
    public User loginVerify(String phone) {
        User one = lambdaQuery().eq(User::getPhone, phone).one();
        if (one == null) {
            one = new User();
            PasswordEncoder delegatingPasswordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
            one.setId(null);
            one.setIsAuth(UserConstant.AppStatus.no);
            one.setIdentity(UserConstant.IsAutu.NO);
            one.setPhone(phone);
            one.setSalt(KeyGenerators.string().generateKey());
            one.setPassword(delegatingPasswordEncoder.encode(one.getPhone() + one.getSalt()));
            one.setImUsername(phone);
            one.setNickName("友伴" + RandomUtils.aAndZ0And9(4));
            one.setPhoto("https://img2.baidu.com/it/u=1090452517,2487311686&fm=253&fmt=auto&app=120&f=JPEG?w=500&h=501");
            save(one);
            one.setRongToken(this.registerRong(one));
            updateById(one);
        }
        return one;
    }

    @Override
    public TokenVO<String> login(LoginRequest request) throws Exception {
        return LoginStrategyContext.getFactory(request.getLoginStrategy())
                .login(request);
    }

    @Override
    public UserBasicsInfo find(Long userId, Long aimUserId) {
        User cache = CacheTemplate.getCache(CacheKey.USER_INFO.getKey(String.valueOf(aimUserId)), User.class, () -> {
            Optional<User> user = lambdaQuery()
                    .eq(User::getId, aimUserId)
                    .oneOpt();
            if (!user.isPresent()) return null;
            CacheTemplate.setCache(CacheKey.USER_INFO.getKey(String.valueOf(aimUserId)), user.get(), 3L, TimeUnit.DAYS);
            return user.get();
        });
        if (CommonUtils.isNull(cache)) return new UserBasicsInfo();
        return userMapBuild(cache, userId, aimUserId);
    }

    @Override
    public UserBasicsInfo userMapBuild(User user, Long userId, Long aimUserId) {
        Integer cache = CacheTemplate.getCache(CacheKey.USER_SPEAK.getKey(aimUserId), Integer.class);

        List<AppDressInfo> dresses = iDressService.userUseDressList(userId);
        Optional<AppDressInfo> first = dresses.stream().filter(res -> res.getDressType().equals(UserConstant.DressType.Tou)).findFirst();
        Optional<AppDressInfo> chat = dresses.stream().filter(res -> res.getDressType().equals(UserConstant.DressType.Chat)).findFirst();
        Optional<AppDressInfo> sound = dresses.stream().filter(res -> res.getDressType().equals(UserConstant.DressType.Sound)).findFirst();

        return UserBasicsInfo.builder()
                .id(user.getId())
                .photo(user.getPhoto())
                .name(user.getName())
                .age(user.getAge())
                .nickName(user.getNickName())
                .imUsername(user.getImUsername())
                .phone(user.getPhone())
                .backgroundUrl(user.getBackgroundUrl())
                .sex(user.getSex())
                .identity(user.getIdentity())
                .interestHobby(user.getInterestHobby())
                .isAuth(user.getIsAuth())
                .latitude(user.getLatitude())
                .longitude(user.getLongitude())
                .province(user.getProvince())
                .personalityName(user.getPersonalityName())
                .placeServer(user.getPlaceServer())
                .loginTime(user.getLoginTime())
                .photoWall(user.getPhotoWall())
                .attentionCount(attentionService.attentionUserCount(user.getId()))
                .fansCount(attentionService.beAttentionCount(user.getId()))
                .isMyFens(attentionService.isMyFens(userId, aimUserId))
                .isAttention(attentionService.isAttention(userId, aimUserId))
                .noteName(Optional.ofNullable(attentionService.findById(userId, aimUserId)).orElse(new Attention()).getNoteName())
                .friendCount(userFriendService.friendCount(aimUserId))
                .backCount(iUserLikeBackService.getUserCount(aimUserId))
                .age(user.getAge())
                .isSpeak(CommonUtils.isNull(cache))
                .banSpeakMin(cache)
                .touDress(first.isPresent() ? first.get() : null)
                .chatDress(chat.isPresent() ? chat.get() : null)
                .soundDress(sound.isPresent() ? sound.get() : null)
                .build();
    }

    @Override
    public String realAuth(Long userId, AppUserAuthRequest realAuthDto) {
        User user = getById(userId);
//        Assert.isTrue(user.getIsAuth().equals(UserConstant.IsAutu.NO), "您已实名认证请勿重复提交");
//        AlipayClient alipayClient = null;
//        try {
//            alipayClient = new DefaultAlipayClient(aliConfig);
//        } catch (AlipayApiException e) {
//            e.printStackTrace();
//        }
//        DatadigitalFincloudGeneralsaasFaceVerificationInitializeRequest request = new DatadigitalFincloudGeneralsaasFaceVerificationInitializeRequest();
//        Map<String, Object> param = new HashMap<>();
//        String faceNum = RandomUtils.aAndZ0And9(32);
//        param.put("outer_order_no", faceNum);
//        param.put("biz_code", "DATA_DIGITAL_BIZ_CODE_FACE_VERIFICATION");
//        param.put("identity_type", "CERT_INFO");
//        param.put("cert_type", "IDENTITY_CARD");
//        param.put("cert_name", realAuthDto.getName());
//        param.put("cert_no", realAuthDto.getCardNumber());
//        request.setBizContent(JSON.toJSONString(param));
//        DatadigitalFincloudGeneralsaasFaceVerificationInitializeResponse response = null;
//        try {
//            response = alipayClient.certificateExecute(request);
//            log.info("实名认证结果：{}", JSON.toJSONString(response));
//        } catch (AlipayApiException e) {
//            e.printStackTrace();
//        }
//        if (response.isSuccess()) {
//            log.info("调用成功:{}", faceNum);
//            //操作成功，将身份证号和真实姓名缓存，验证成功后更新，否则舍弃
//            CacheTemplate.setCache(UserConstant.UserCacheTemplate.auth + userId, realAuthDto);
//
//            user.setName(realAuthDto.getName());
//            user.setCardNum(realAuthDto.getCardNumber());
//            updateById(user);
//            return response.getCertifyId();
//        } else {
//            log.info("调用失败:{}", faceNum + ":" + response.getSubMsg());
//            Assert.isTrue(false, "实名认证失败请检查姓名与身份证号码是否有误");
//        }
        return "";
    }

    @Override
    public boolean realAuthResult(String certifyId, Long userId) {
//        Assert.isTrue(StringUtils.hasText(certifyId), "实名认证结果ID不能为空");
//        User user = getById(userId);
//        AlipayClient alipayClient = null;
//        try {
//            alipayClient = new DefaultAlipayClient(aliConfig);
//        } catch (AlipayApiException e) {
//            e.printStackTrace();
//        }
//        DatadigitalFincloudGeneralsaasFaceVerificationQueryRequest request = new DatadigitalFincloudGeneralsaasFaceVerificationQueryRequest();
//        Map<String, Object> param = new HashMap<>();
//        param.put("certify_id", certifyId);
//        param.put("need_alive_photo", "N");
//        request.setBizContent(JSON.toJSONString(param));
//        DatadigitalFincloudGeneralsaasFaceVerificationQueryResponse response = null;
//        try {
//            response = alipayClient.certificateExecute(request);
//            log.info("查询认证结果：{}", response);
//        } catch (AlipayApiException e) {
//            e.printStackTrace();
//        }
//        if (response.isSuccess()) {
//            if (response.getCode().equals("10000")) {
//                log.info("支付宝认证成功");
//                //认证成功，回写真实姓名，身份证号,认证状态，清空缓存
//                AppUserAuthRequest cache = CacheTemplate.getCache(UserConstant.UserCacheTemplate.auth + userId, AppUserAuthRequest.class);
//                if (!CommonUtils.isNull(cache)) {
//                    char c = cache.getCardNumber().charAt(16);
//                    int sexNum = Integer.parseInt(String.valueOf(c));
//                    user.setSex(sexNum % 2);
//                    user.setIsAuth(UserConstant.AppStatus.yes);
//                    updateById(user);
//                    //清除缓存数据
//                    CacheTemplate.clear(UserConstant.UserCacheTemplate.auth + userId);
//                }
//            }
//        } else {
//            log.info("调用失败");
//        }
        return true;
    }

    @Override
    public void setTeenager(Long userId, AppUserSetTeenagerRequest request) {
        User user = getById(userId);
        PasswordEncoder passwordEncoder = PasswordEncoderFactories.createDelegatingPasswordEncoder();
        if (request.getType().equals(UserConstant.IsAutu.NO)) {
            Assert.isTrue(user.getIsAdolescent().equals(UserConstant.IsAutu.NO), "您已设置青少年模式请勿重复设置");
            user.setSalt(KeyGenerators.string().generateKey());
            user.setTutelageWord(passwordEncoder.encode(request.getTutelageWord() + user.getSalt()));
            user.setIsAdolescent(UserConstant.IsAutu.YES);
        } else {
            Assert.isTrue(StringUtils.hasText(user.getTutelageWord()), "暂未设置监护密码");
            Assert.isTrue(passwordEncoder.matches(request.getTutelageWord() + user.getSalt(), user.getTutelageWord()), "监护密码错误!");
            user.setIsAdolescent(UserConstant.IsAutu.NO);
        }
        updateById(user);
    }

    @Override
    public User findUserInfo(Long userId) {
        return getById(userId);
    }

    @Override
    public AppUser getUserById(Long userId) {
        User cache = CacheTemplate.getCache(CacheKey.USER_INFO.getKey(String.valueOf(userId)), User.class, () -> {
            Optional<User> user = lambdaQuery()
                    .eq(User::getId, userId)
                    .oneOpt();
            if (!user.isPresent()) return null;
            CacheTemplate.setCache(CacheKey.USER_INFO.getKey(String.valueOf(userId)), user.get(), 3L, TimeUnit.DAYS);
            return user.get();
        });
        AppUser appUser = new AppUser();
        BeanUtils.copyProperties(cache, appUser);

        List<AppDressInfo> dresses = iDressService.userUseDressList(userId);
        for (AppDressInfo dress : dresses) {
            if (dress.getDressType().equals(UserConstant.DressType.Tou)) {
                appUser.setTouDress(dress);
            }
            if (dress.getDressType().equals(UserConstant.DressType.Sound)) {
                appUser.setSoundDress(dress);
            }
            if (dress.getDressType().equals(UserConstant.DressType.Chat)) {
                appUser.setChatDress(dress);
            }
        }
        return appUser;
    }


    /**
     * 向融云注册用户拿到融云token
     */
    private String registerRong(User user) {
        io.rong.methods.user.User rongUser = rongCloud.user;
        String token = "";
        try {
            UserModel userModel = new UserModel();
            userModel.setId(String.valueOf(user.getId()));
            userModel.setName(user.getNickName());
            userModel.setPortrait(user.getPhoto());
            TokenResult register = rongUser.register(userModel);
            token = register.getToken();
        } catch (Exception e) {
            log.info("融云注册用户失败 -------- e={}", e.toString());
        }
        return token;
    }
}
